package org.third.common.exception;

import javax.servlet.http.HttpServletRequest;

import org.postgresql.util.PSQLException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.third.common.utils.HttpUtils;
import org.third.integration.kubernates.cmd.imp.exp.NotValidK8sYamlException;
import org.third.integration.kubernates.cmd.imp.exp.RequestApiServerException;

import com.google.common.base.Throwables;

@ControllerAdvice
@RestController
public class GlobalExceptionHandler {

	@ResponseStatus(HttpStatus.FORBIDDEN)
	@ExceptionHandler(value = ForbiddenException.class)
	@ResponseBody
	public ErrorInfo<String> handleForbiddenException(HttpServletRequest req, ForbiddenException e) {
		ErrorInfo<String> r = new ErrorInfo<String>();
		r.setMessage(HttpUtils.encodeHtml(e.getMessage()));
		r.setCode(HttpStatus.FORBIDDEN.value());
		r.setUrl(req.getRequestURL().toString());
		return r;
	}

	@ResponseStatus(HttpStatus.NOT_FOUND)
	@ExceptionHandler(value = NotFoundException.class)
	@ResponseBody
	public ErrorInfo<String> handleBaseException(HttpServletRequest req, NotFoundException e) {
		ErrorInfo<String> r = new ErrorInfo<String>();
		r.setMessage(HttpUtils.encodeHtml(e.getMessage()));
		r.setCode(HttpStatus.NOT_FOUND.value());
		r.setUrl(req.getRequestURL().toString());
		return r;
	}

	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(value = BadRequestException.class)
	@ResponseBody
	public ErrorInfo<String> handleBadRequestException(HttpServletRequest req, BadRequestException e) {
		ErrorInfo<String> r = new ErrorInfo<String>();
		r.setMessage(HttpUtils.encodeHtml(e.getMessage()));
		r.setCode(HttpStatus.BAD_REQUEST.value());
		r.setUrl(req.getRequestURL().toString());
		return r;
	}

	@ResponseStatus(HttpStatus.REQUEST_TIMEOUT)
	@ExceptionHandler(value = RequestTimeoutException.class)
	@ResponseBody
	public ErrorInfo<String> handleRequestTimeoutException(HttpServletRequest req, RequestTimeoutException e) {
		ErrorInfo<String> r = new ErrorInfo<String>();
		r.setMessage(HttpUtils.encodeHtml(e.getMessage()));
		r.setCode(HttpStatus.REQUEST_TIMEOUT.value());
		r.setUrl(req.getRequestURL().toString());
		return r;
	}

	@ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE)
	@ExceptionHandler(value = ServiceUnavailableException.class)
	@ResponseBody
	public ErrorInfo<String> handleServiceUnavailableException(HttpServletRequest req, ServiceUnavailableException e) {
		ErrorInfo<String> r = new ErrorInfo<String>();
		r.setMessage(HttpUtils.encodeHtml(e.getMessage()));
		r.setCode(HttpStatus.SERVICE_UNAVAILABLE.value());
		r.setUrl(req.getRequestURL().toString());
		return r;
	}

	@ExceptionHandler(value = InvalidDataAccessResourceUsageException.class)
	public ResponseEntity<?> handleInvalidDataAccessResourceUsageException(HttpServletRequest req,
			InvalidDataAccessResourceUsageException e) {
		boolean isNeedCatch = false;
		if (req.getMethod().equals("POST")) {
			if (Throwables.getRootCause(e) instanceof PSQLException) {
				for (String regex : ExceptionConfig.URL_WILL_RETRY_LIST) {
					if (req.getRequestURI().matches(regex)) {
						isNeedCatch = true;
					}
				}
			}

		}
		if (isNeedCatch) {
			ErrorInfo<String> errorInfo = new ErrorInfo<String>();
			errorInfo.setCode(449);
			errorInfo.setMessage(
					"warning: some error have occurred when insert into Database, please check whether nfs server is fine and retry");
			errorInfo.setUrl(req.getRequestURL().toString());
			return ResponseEntity.status(449).body(errorInfo);
		} else {
			ErrorInfo<String> errorInfo = new ErrorInfo<String>();
			errorInfo.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
			errorInfo.setMessage(e.getMessage());
			errorInfo.setUrl(req.getRequestURL().toString());
			errorInfo.setData(e.getCause().toString());
			return new ResponseEntity<ErrorInfo>(errorInfo, HttpStatus.INTERNAL_SERVER_ERROR);
		}
	}

//	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
//	@ExceptionHandler(value = Exception.class)
//	@ResponseBody
//	public ErrorInfo<String> handleBaseException(HttpServletRequest req,
//			Exception e) {
//		ErrorInfo<String> r = new ErrorInfo<String>();
//		r.setMessage(e.getMessage());
//		r.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
//		r.setUrl(req.getRequestURL().toString());
//		return r;
//	}

	@ResponseStatus(HttpStatus.PRECONDITION_REQUIRED)
	@ExceptionHandler(value = NotValidK8sYamlException.class)
	@ResponseBody
	public ErrorInfo<String> handleBaseException(HttpServletRequest req, NotValidK8sYamlException e) {
		ErrorInfo<String> r = new ErrorInfo<String>();
		r.setMessage("K8s Yaml File Valid:" + HttpUtils.encodeHtml(e.getMessage()));
		r.setCode(HttpStatus.PRECONDITION_REQUIRED.value());
		r.setUrl(req.getRequestURL().toString());
		return r;
	}

	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(value = RequestApiServerException.class)
	@ResponseBody
	public ErrorInfo<String> handleBaseException(HttpServletRequest req, RequestApiServerException e) {
		ErrorInfo<String> r = new ErrorInfo<String>();
		r.setMessage("Request Api Server Failed:" + HttpUtils.encodeHtml(e.getMessage()));
		r.setCode(HttpStatus.BAD_REQUEST.value());
		r.setUrl(req.getRequestURL().toString());
		return r;
	}

	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ExceptionHandler(value = ConvertJsonException.class)
	@ResponseBody
	public ErrorInfo<String> handleConvertJsonException(HttpServletRequest req, ConvertJsonException e) {
		ErrorInfo<String> r = new ErrorInfo<String>();
		r.setMessage("Convert Json Exception:" + HttpUtils.encodeHtml(e.getMessage()));
		r.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
		r.setUrl(req.getRequestURL().toString());
		return r;
	}

	@ExceptionHandler(ThreadUnDoneException.class)
	@ResponseStatus(HttpStatus.LOCKED)
	@ResponseBody
	public ErrorInfo<String> processThreadUnDoneException(HttpServletRequest req, ThreadUnDoneException e) {
		ErrorInfo<String> r = new ErrorInfo<String>();
		r.setMessage("ThreadUnDoneException Exception:" + HttpUtils.encodeHtml(e.getMessage()));
		r.setCode(HttpStatus.LOCKED.value());
		r.setUrl(req.getRequestURL().toString());
		return r;
	}

	@ExceptionHandler(ImagePullBackOffException.class)
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ResponseBody
	public ErrorInfo<String> processImagePullBackOffException(HttpServletRequest req, ImagePullBackOffException e) {
		ErrorInfo<String> r = new ErrorInfo<String>();
		r.setMessage("ImagePullBackOffException Exception:" + HttpUtils.encodeHtml(e.getMessage()));
		r.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
		r.setUrl(req.getRequestURL().toString());
		return r;
	}
}
